<?php

namespace App\Export;

use Illuminate\Support\Collection;
use JetBrains\PhpStorm\NoReturn;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\WithHeadings;
use Maatwebsite\Excel\Concerns\WithEvents;
use Maatwebsite\Excel\Events\AfterSheet;
class DoneOrderExport implements FromCollection, WithHeadings, withEvents
{
    private array $data = [];
    private array $rows = [];

    /**
     * 初始化
     * @param $data
     */
    #[NoReturn] public function __construct($data)
    {
        $this->data = $data;
        $this->setRows($data);
    }

    /**
     * 表头设置
     * @return string[]
     */
    public function headings(): array
    {
        return [
            '商家名称',
            '商品名称',
            '商品规格',
            '重量',
            '单价',
            '数量',
            '总价',
            '合计',
            '退货款',
            '备注',
        ];
    }

    /**
     * 数据格式化
     * @return Collection
     */
    public function collection(): Collection
    {
        $list = [];
        foreach ($this->data as $key => $goods) {
            $list[] = [
                'sname'         => $goods->sname,
                'goods_name'    => $goods->goods_name,
                'spec'          => $goods->color . ';' . $goods->size,
                'weight'        => $goods->weight,
                'price'         => $goods->price,
                'goods_num'     => $goods->goods_num,
                'total'         => $goods->total,
                'sum'           => $this->getSum($key),
                'minus'         => 0 - $goods->minus,
                'goods_remark'  => $goods->goods_remark
            ];
        }
        return new Collection($list);
    }

    /**
     * 注册事件，合并单元格
     * @return array
     */
    public function registerEvents(): array
    {
        $rows = array_map(function ($v) {
            return implode(',', $v);
        }, $this->rows);
        $groupRows = array_unique($rows);
        return [
            AfterSheet::class => function (AfterSheet $event) use ($groupRows) {
                foreach ($groupRows as $rowString) {
                    $rows = explode(',', $rowString);
                    if (count($rows) > 1 && $rows[0] != '') {
                        $start = intval($rows[0]) + 2;
                        $end = intval($rows[count($rows) - 1]) + 2;
                        $event->sheet->getDelegate()->mergeCells("A{$start}:A{$end}");
                        $event->sheet->getDelegate()->mergeCells("H{$start}:H{$end}");
                        $event->sheet->getDelegate()->mergeCells("I{$start}:I{$end}");
                    }
                }
            }
        ];
    }

    /**
     * 获取商家订单总金额
     * @param $key
     * @return int|float
     */
    private function getSum($key): int|float
    {
        $keyRows = $this->rows[$key];
        $sum = 0;
        if (count($keyRows) > 1) {
            foreach ($keyRows as $k) {
                $sum += $this->data[$k]->total;
            }
        } else
            $sum = $this->data[$key]->total;
        return $sum;
    }

    /**
     * 设置相邻同商家归并
     * @param $data
     * @return void
     */
    private function setRows($data): void
    {
        $supplies = [];
        foreach ($data as $key => $goods) {
            $supplies[$key] = $goods->sid;
        }
        foreach ($supplies as $key => $sid) {
            $this->rows[$key] = $this->deepestSearch($key, $supplies);
        }
    }

    /**
     * 最大深度搜索+求和
     * @param $key
     * @param $supplies
     * @return array
     */
    private function deepestSearch($key, $supplies): array
    {
        $search = $supplies[$key];
        $rows = [];
        for($i = $key; $i >= 0; $i--) {
            if ($supplies[$i] == $search) {
                $rows[] = $i;
            } else {
                break;
            }
        }
        for($i = $key + 1; $i < count($supplies); $i++) {
            if ($supplies[$i] == $search) {
                $rows[] = $i;
            } else {
                break;
            }
        }
        sort($rows);
        return $rows;
    }
}
